home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 16 code / CollaboDraw / mystandardmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-24  |  23.4 KB  |  1,051 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------------------------
  2.  *
  3.  * Simple Sample PowerTalk Application Framework
  4.  *
  5.  * ©1991-1993 Apple Computer
  6.  *
  7.  -------------------------------------------------------------------------------------*/
  8. /*
  9.  * mystandardmail.c -- powertalk-specific routines
  10.  *
  11.  * change history:
  12.  *
  13.  * SJF        08/23/93        1.0f1        update to final headers, fix comments
  14.  * SJF        04/21/93        1.0b2        update to b2
  15.  * SJF        03/01/93        1.0b1        added digital signatures
  16.  * SJF        02/09/93        1.0b1        update to b1
  17.  * SJF        10/13/92        1.0d4        update to a11
  18.  * SJF        09/09/92        1.0d3        update to a9
  19.  * SJF        05/07/92        1.0d2        update to a6
  20.  * SJF        11/06/91        1.0d1        initial coding
  21.  *
  22.  */
  23.  
  24. #ifndef __TYPES__
  25. #include <Types.h>
  26. #endif
  27.  
  28. #ifndef __MENUS__
  29. #include <Menus.h>
  30. #endif
  31.  
  32. #ifndef __SCRIPT__
  33. #include <Script.h>
  34. #endif
  35.  
  36. #ifndef __FILES__
  37. #include <Files.h>
  38. #endif
  39.  
  40. #ifndef __FOLDERS__
  41. #include <Folders.h>
  42. #endif
  43.  
  44. #ifndef __ERRORS__
  45. #include <Errors.h>
  46. #endif
  47.  
  48. #ifndef __PACKAGES__
  49. #include <Packages.h>
  50. #endif
  51.  
  52. #ifndef __TRAPS__
  53. #include <Traps.h>
  54. #endif
  55.  
  56. #ifndef __GESTALTEQU__
  57. #include <GestaltEqu.h>
  58. #endif
  59.  
  60. #ifndef __TOOLUTILS__
  61. #include <ToolUtils.h>
  62. #endif
  63.  
  64. #ifndef __RESOURCES__
  65. #include <Resources.h>
  66. #endif
  67.  
  68. #ifndef __OCE__
  69. #include <OCE.h>
  70. #endif
  71.  
  72. #ifndef __OCESTANDARDDIRECTORY__
  73. #include <OCEStandardDirectory.h>
  74. #endif
  75.  
  76. #ifndef __OCESTANDARDMAIL__
  77. #include <OCEStandardMail.h>
  78. #endif
  79.  
  80. #ifndef __OCEAUTHDIR__
  81. #include <OCEAuthDir.h>
  82. #endif
  83.  
  84. #ifndef __OCEERRORS__
  85. #include <OCEErrors.h>
  86. #endif
  87.  
  88. #include <string.h>
  89.  
  90. #include "const.h"
  91. #include "mytypes.h"
  92. #include "globals.h"
  93. #include "windowstuff.h"
  94. #include "draw.window.h"
  95. #include "draw.mailer.window.h"
  96. #include "utils.h"
  97. #include "myevents.h"
  98. #include "windutils.h"
  99. #include "strconst.h"
  100. #include "commands.h"
  101. #include "mymenus.h"
  102. #include "digisig.h"
  103.  
  104. #include "mystandardmail.h"
  105.  
  106. pascal void DrawImageProc(long refcon, Boolean inColor);
  107.  
  108.  
  109. /** HasStandardMail
  110.  **
  111.  ** returns true only of Standard Mail package is available and running
  112.  **/
  113. Boolean HasStandardMail(void)
  114. {
  115.     OSErr err;
  116.     long response;
  117.     
  118.     err = Gestalt(gestaltSMPMailerVersion,&response);
  119.     if ((err!=noErr) || (response==0))
  120.         return false;
  121.     
  122.     return true;
  123. }
  124.  
  125.  
  126. /** InitStandardMail
  127.  **
  128.  ** initializes the standard mail packages by calling SMPInitMailer with the version of
  129.  ** AOCE that we support (passing in an earlier version of AOCE than the user is running
  130.  ** will put AOCE in that version's compatibility mode for your application, passing a later
  131.  ** version should return an error
  132.  **/
  133. OSErr InitStandardMail(void)
  134. {
  135.     OSErr err;
  136.     
  137.     SetCursor(&gWatchCursor);
  138.     err = SMPInitMailer(kSMPVersion);
  139.     SetCursor(&qd.arrow);
  140.     return err;
  141. }
  142.  
  143.  
  144. /** CommAddRemoveMailer
  145.  **
  146.  ** called when the user selects either add or remove mailer from the mail menu.
  147.  ** this function calls either add mailer if the window has no mailer or remove mailer if it does
  148.  **/
  149. void CommAddRemoveMailer(WindowPtr window)
  150. {    
  151.     SetCursor(&gWatchCursor);    // this may take some time
  152.  
  153.     if (IsWindowType(window,kDrawWindow))    // we add mailers to drawing windows
  154.         CommAddMailer(window);
  155.     else if (IsWindowType(window,kDrawMailerWindow))
  156.         CommRemoveMailer(window);
  157.     
  158.     SetCursor(&qd.arrow);        // done waiting
  159. }
  160.  
  161.  
  162. /** CommAddMailer
  163.  **
  164.  ** adds a mailer to an existing window
  165.  **/
  166. void CommAddMailer(WindowPtr window)
  167. {
  168.     Boolean chFlag = false;
  169.     GrafPtr savePort;
  170.     Rect rectToInval;
  171.     
  172.     SendWindowMessage(window,kDeactivateMessage,&chFlag);    // send the drawing a deactivate
  173.  
  174.     GetPort(&savePort);
  175.     SetPort(window);
  176.     rectToInval = window->portRect;
  177.     rectToInval.bottom -= kScrollBarWidth;
  178.     rectToInval.right -= kScrollBarWidth;
  179.     EraseRect(&rectToInval);
  180.     InvalRect(&rectToInval);    // invalidate the entire window
  181.     SetPort(savePort);
  182.  
  183.     MakeMailerFromDrawing(window);
  184.     SendWindowMessage(window,kActivateMessage,&chFlag);
  185. }
  186.  
  187.  
  188.  
  189. /** CommRemoveMailer
  190.  **
  191.  ** removes a mailer from an existing window
  192.  **/
  193. void CommRemoveMailer(WindowPtr window)
  194. {
  195.     Boolean chFlag = false;
  196.     GrafPtr savePort;
  197.     Rect rectToInval;
  198.     
  199.     SendWindowMessage(window,kDeactivateMessage,&chFlag);
  200.  
  201.     GetPort(&savePort);
  202.     SetPort(window);
  203.     rectToInval = window->portRect;
  204.     rectToInval.bottom -= kScrollBarWidth;
  205.     rectToInval.right -= kScrollBarWidth;
  206.     EraseRect(&rectToInval);
  207.     InvalRect(&rectToInval);
  208.     SetPort(savePort);
  209.  
  210.     MakeDrawingFromMailer(window);
  211.     SendWindowMessage(window,kActivateMessage,&chFlag);
  212. }
  213.  
  214.  
  215. /** CommSendLetter
  216.  **
  217.  ** sends a letter using SMPBeginSend/SMPEndSend
  218.  **/
  219. void CommSendLetter(WindowPtr window)
  220. {
  221.     char hState;
  222.     WInfoPtr infoPtr;
  223.     OSErr err;
  224.     Boolean mustAddContent;
  225.     Str255 docTitle;
  226.     Str255 nativeFormat;
  227.     StringPtr nativeFormatArray[1];
  228.     OSType letterCreator;
  229.     OSType letterType;
  230.     
  231.     GetResString(nativeFormat,kAppNameID,kAppName);
  232.  
  233.     infoPtr = BeginWindowAccess(window,&hState);
  234.         
  235.     GetWTitle(window,docTitle);
  236.     nativeFormatArray[0] = (StringPtr)nativeFormat;
  237.     SetCursor(&qd.arrow);
  238.     err = SMPSendOptionsDialog(window,docTitle,nativeFormatArray,1,
  239.             kSMPNativeMask|kSMPImageMask|kSMPStandardInterchangeMask,&gPreferences.sendFormat,
  240.             nil,0L,&gPreferences.sendFormat,&gPreferences.sendOptions);
  241.     
  242.     if (err==userCanceledErr)
  243.         return;
  244.         
  245.     if (err!=noErr) {
  246.         DoError(err);
  247.         return;
  248.     }
  249.         
  250.     SetCursor(&gWatchCursor);
  251.  
  252.     // use our creator if we have native format, else use AppleMail creator
  253.     if ((gPreferences.sendFormat.whichFormats & kSMPNativeMask)!=0) {
  254.         letterCreator = kAppCreator;
  255.         letterType = kCDLtrMsgType;
  256.     }
  257.     else {
  258.         letterCreator = 'lap2';
  259.         letterType = kMailLtrMsgType;
  260.     }
  261.     err = SMPBeginSend(window,letterCreator,letterType,&gPreferences.sendOptions,&mustAddContent);
  262.     if (err!=noErr) {
  263.         SetCursor(&qd.arrow);
  264.         EndWindowAccess(window,hState);
  265.         DoError(err);
  266.         return;
  267.     }
  268.  
  269.     if (mustAddContent) {
  270.         if (err==noErr)
  271.             err = AddLetterBlocks(window,infoPtr,&gPreferences.sendFormat,
  272.                         nativeFormatArray[gPreferences.sendFormat.whichNativeFormat]);
  273.         if (err!=noErr)
  274.             DoError(err);
  275.     }
  276.             
  277.     err = SMPEndSend(window,(err==noErr));
  278.     if (err!=noErr)
  279.         DoError(err);
  280.     
  281.     EndWindowAccess(window,hState);
  282.  
  283.     if ((err==noErr) && gPreferences.closeOnSend)
  284.         CommCloseWindow(window);
  285.         
  286.     SetCursor(&qd.arrow);        // done waiting
  287. }
  288.  
  289.  
  290. /** LoSaveLetter
  291.  **
  292.  ** saves a letter using SMPBeginSave/SMPEndSave
  293.  **/
  294. OSErr LoSaveLetter(WindowPtr window,WInfoPtr infoPtr,SMPSaveType saveType)
  295. {
  296.     OSErr err,err2;
  297.     FSSpec *fSpec;
  298.     Boolean mustAddContent;
  299.     Str255 nativeFormat;
  300.     
  301.     GetResString(nativeFormat,kAppNameID,kAppName);
  302.  
  303.     err = err2 = noErr;
  304.     
  305.     SetCursor(&gWatchCursor);    // this may take some time
  306.  
  307.     fSpec = &infoPtr->fileSpec;
  308.     err = SMPBeginSave(window,fSpec,kAppCreator,kCDLtrMsgType,saveType,&mustAddContent);
  309.     if (err!=noErr) {
  310.         SetCursor(&qd.arrow);        // done waiting
  311.         return err;
  312.     }
  313.  
  314.     if (mustAddContent) {
  315.         if (err==noErr)
  316.             err2 = AddLetterBlocks(window,infoPtr,nil,nativeFormat);
  317.         else
  318.             err2 = noErr;
  319.     }
  320.     
  321.     err = SMPEndSave(window,(err==noErr));
  322.     if (err!=noErr)
  323.         return err;
  324.  
  325.     if (err==noErr) {
  326.         infoPtr->otherData[kLastChangedData] = 0;
  327.     }
  328.     
  329.     SetCursor(&qd.arrow);        // done waiting
  330.     
  331.     if (err==noErr)
  332.         return err2;
  333.     else
  334.         return err;
  335. }
  336.  
  337.  
  338. /** LoSaveLetter
  339.  **
  340.  ** saves a letter using SMPBeginSave/SMPEndSave
  341.  **/
  342. void CommReply(WindowPtr window,Boolean replyToAll)
  343. {
  344.     WindowPtr replyWindow;
  345.     Point topLeft = {0,0};
  346.     Str255 newTitle;
  347.     Rect newWindRect;
  348.     Point *ptPtr;
  349.     OSErr err;
  350.     
  351.     GetResString(newTitle,kDefaultFilenameID,kDefaultFilename);
  352.     newWindRect = window->portRect;
  353.     SetPort(window);
  354.     ptPtr = (Point *)&newWindRect;
  355.     LocalToGlobal(ptPtr++);
  356.     LocalToGlobal(ptPtr);
  357.     OffsetRect(&newWindRect,kWindowOffset,kWindowOffset);
  358.     
  359.     replyWindow = MakeWindow(kDrawMailerWindow,&newWindRect,newTitle,false);
  360.     err = SMPMailerReply(window,replyWindow,replyToAll,topLeft,true,true,kDefaultIdentity,nil,0L);
  361.     if (err!=noErr)
  362.         DoError(err);
  363.     ShowWindow(replyWindow);
  364. }
  365.  
  366.  
  367. /** CommForward
  368.  **
  369.  ** forwards a letter (adds an additional mailer)
  370.  **/
  371. void CommForward(WindowPtr window)
  372. {
  373.     WInfoPtr infoPtr;
  374.     char hState;
  375.     
  376.     OSErr err;
  377.     
  378.     infoPtr = BeginWindowAccess(window,&hState);
  379.  
  380.     HandleExpand(window,infoPtr);    // expand the window before doing the forward
  381.         
  382.     err = SMPMailerForward(window,kDefaultIdentity);
  383.     if (err!=noErr)
  384.         DoError(err);
  385.     
  386.     infoPtr->saved = false;
  387.     
  388.     DMailerActivateWindow(window,infoPtr,nil);
  389.     EndWindowAccess(window,hState);
  390. }
  391.  
  392.  
  393. /** CommAdjacentLetter
  394.  **
  395.  ** opens the next available letter of our type
  396.  **/
  397. void CommAdjacentLetter(void)
  398. {
  399.     OSErr err,err2;
  400.     LetterDescriptor newLetter,**oldLetter;
  401.     OSType ltrType;
  402.     WindowPtr window;
  403.     WInfoPtr infoPtr;
  404.     char hState,hState2;
  405.     SMPMailerState state;
  406.     
  407.     SetCursor(&gWatchCursor);
  408.  
  409.     ltrType = kCDLtrMsgType;
  410.     err = SMPGetNextLetter(<rType,1,&newLetter);
  411.     
  412.     for (window=MyFrontWindow(); window!=nil; window=(WindowPtr)((WindowPeek)window)->nextWindow) {
  413.         infoPtr = BeginWindowAccess(window,&hState);
  414.         if (IsWindowType(window,kDrawMailerWindow)) {
  415.             err2 = SMPGetMailerState(window, &state);
  416.             if ((err2==noErr)&&(state.hasBeenReceived)) {
  417.                 oldLetter = (LetterDescriptor **)infoPtr->otherData[kLetterDescData];
  418.                 hState2 = HGetState((Handle)oldLetter);
  419.                 HLock((Handle)oldLetter);
  420.                 if (SameLetter(*oldLetter,&newLetter))
  421.                     err = kInternalError;                // don't open letter if it's already open
  422.                 HSetState((Handle)oldLetter,hState2);
  423.             }
  424.         }
  425.         EndWindowAccess(window,hState);
  426.     }
  427.     
  428.     if (err==noErr) {
  429.         err = LoOpen(false,nil,&newLetter.u.mailboxSpec,true,&window);
  430.         if (err!=noErr)
  431.             DoError(err);
  432.     }
  433.     else
  434.         SysBeep(1);        // no adjacent letters
  435.  
  436.     SetCursor(&qd.arrow);        
  437. }
  438.  
  439.  
  440. /** CommTagLetter
  441.  **
  442.  ** brings up a dialog allowing the user to tag the frontmost letter
  443.  **/
  444. void CommTagLetter(void)
  445. {
  446.     RString32 tag;
  447.     OSErr err;
  448.     
  449.     tag.dataLength = 0;
  450.     err = SMPTagDialog(MyFrontWindow(),&tag);
  451.     if ((err!=noErr) && (err!=userCanceledErr))
  452.         DoError(err);
  453. }
  454.  
  455.  
  456. /** ProcessPowerTalkEvent
  457.  **
  458.  ** used as a pre-filter for all events when a mailer window is frontmost
  459.  **/
  460. OSErr ProcessPowerTalkEvent(WindowPtr window,WInfoPtr infoPtr,const EventRecord *ev,
  461.                             SMPMailerResult *mailResult)
  462. {
  463.     #pragma unused (window,infoPtr)
  464.     
  465.     return SMPMailerEvent(ev,mailResult,nil,0L);
  466. }
  467.  
  468.  
  469. /** ProcessPowerTalkWhatHappened
  470.  **
  471.  ** take action depending on what happened when we passed an event to PowerTalk
  472.  **/
  473. Boolean ProcessPowerTalkWhatHappened(WindowPtr window,WInfoPtr infoPtr,SMPMailerResult mailResult)
  474. {
  475.     OSErr err;
  476.     SMPMailerState state;
  477.     long *lastChanged;
  478.     
  479.     // see if the mailer has changed
  480.         
  481.     err = SMPGetMailerState(window, &state);
  482.     if (err != noErr)
  483.         DoError(err);
  484.  
  485.     lastChanged = (long *) &infoPtr->otherData[kLastChangedData];
  486.     if (*lastChanged!=state.changeCount) {
  487.         *lastChanged = state.changeCount;
  488.         infoPtr->changed = true;
  489.         FixMailerMenus(window,infoPtr);
  490.     }
  491.  
  492.     // track if copy window is visible
  493.     
  494.     if ((mailResult & kSMPCreateCopyWindowMask) != 0)
  495.         gHasCopyWindow = true;
  496.     
  497.     if ((mailResult & kSMPDisposeCopyWindowMask) != 0)
  498.         gHasCopyWindow = false;
  499.     
  500.     // track if the mailer has been expanded or contracted
  501.         
  502.     if ((mailResult & kSMPContractedMask) != 0)
  503.         HandleContract(window,infoPtr);
  504.  
  505.     if ((mailResult & kSMPExpandedMask) != 0)
  506.         HandleExpand(window,infoPtr);
  507.  
  508.     if (((mailResult & kSMPMailerBecomesTargetMask) != 0) ||
  509.         ((mailResult & kSMPAppBecomesTargetMask) != 0))
  510.             FixMailerMenus(window,infoPtr);
  511.     
  512.     // actually, we want to check the menus for *every* event that the mailer handles completely,
  513.     // since we may need to change the Undo item in the File menu to keep it up to date
  514.     
  515.     if ((mailResult & kSMPAppShouldIgnoreEventMask) != 0)
  516.         FixMailerMenus(window,infoPtr);
  517.         
  518.     if ((mailResult & kSMPAppMustHandleEventMask) != 0)
  519.         return false;    // app must handle this event
  520.     else return true;    // mailer handled this event completely
  521. }
  522.  
  523.  
  524. /** MakeMailerFromDrawing
  525.  **
  526.  ** called when a mailer is added to a drawing window
  527.  **/
  528. void MakeMailerFromDrawing(WindowPtr window)
  529. {
  530.     WInfoPtr infoPtr;
  531.     char hState;
  532.     Point topLeft = {0,0};
  533.     OSErr err;
  534.     short mWidth,contHeight,expHeight;
  535.     
  536.     SetWindowKind(window,kDrawMailerWindow);
  537.  
  538.     infoPtr = BeginWindowAccess(window,&hState);
  539.  
  540.     SetDMailerMethods(infoPtr);
  541.     infoPtr->otherFlags[kMailerExpanded] = gPreferences.expandOnCreate;
  542.     
  543.     if (infoPtr->fRefNum) {
  544.         err = FSClose(infoPtr->fRefNum);
  545.         if (err!=noErr)
  546.             DoError(err);
  547.         infoPtr->fRefNum = 0;
  548.     }
  549.     if (infoPtr->resRefNum) {
  550.         DSIGCopySigsToTemp(infoPtr);
  551.         CloseResFile(infoPtr->resRefNum);
  552.         err = ResError();
  553.         if (err!=noErr)
  554.             DoError(err);
  555.         infoPtr->resRefNum = 0;
  556.     }
  557.  
  558.     infoPtr->saved = false;
  559.     infoPtr->changed = true;
  560.     
  561.     infoPtr->otherData[kLetterDescData] = nil;
  562.     
  563.     err = SMPNewMailer(window,topLeft,true,gPreferences.expandOnCreate,kDefaultIdentity,nil,0L);
  564.     if (err!=noErr)
  565.         DoError(err);
  566.     
  567.     err = SMPGetDimensions(&mWidth,&contHeight,&expHeight);
  568.     if (err!=noErr)
  569.         DoError(err);
  570.     if (infoPtr->otherFlags[kMailerExpanded])
  571.         infoPtr->topIndent = expHeight;
  572.     else
  573.         infoPtr->topIndent = contHeight;
  574.         
  575.     MoveScrollBars(window);
  576.  
  577.     EndWindowAccess(window,hState);
  578. }
  579.  
  580.  
  581. /** MakeDrawingFromMailer
  582.  **
  583.  ** called when a mailer is removed from a letter window (turning it into a drawing only)
  584.  **/
  585. void MakeDrawingFromMailer(WindowPtr window)
  586. {
  587.     WInfoPtr infoPtr;
  588.     char hState;
  589.     
  590.     OSErr err;
  591.     
  592.     if (!CanCloseLetter(window))    // make sure no open enclosures
  593.         return;
  594.  
  595.     err = SMPDisposeMailer(window,&gPreferences.closeOptions);
  596.     if (err!=noErr)
  597.         DoError(err);
  598.     
  599.     SetWindowKind(window,kDrawWindow);
  600.  
  601.     infoPtr = BeginWindowAccess(window,&hState);
  602.  
  603.     infoPtr->topIndent = 0;
  604.     if (!CheckPageSize(window,infoPtr))        // draw area may have gotten too big for us
  605.         MoveScrollBars(window);
  606.     
  607.     if (infoPtr->fRefNum) {
  608.         err = FSClose(infoPtr->fRefNum);
  609.         if (err!=noErr)
  610.             DoError(err);
  611.         infoPtr->fRefNum = 0;
  612.     }
  613.     if (infoPtr->resRefNum) {
  614.         DSIGCopySigsToTemp(infoPtr);
  615.         CloseResFile(infoPtr->resRefNum);
  616.         err = ResError();
  617.         if (err!=noErr)
  618.             DoError(err);
  619.         infoPtr->resRefNum = 0;
  620.     }
  621.  
  622.     infoPtr->saved = false;
  623.     infoPtr->changed = true;
  624.  
  625.     if (infoPtr->otherData[kLetterDescData])
  626.         DisposHandleChk((Handle)infoPtr->otherData[kLetterDescData]);
  627.         
  628.     SetDrawMethods(infoPtr);
  629.  
  630.     EndWindowAccess(window,hState);
  631. }
  632.  
  633.  
  634. /** FixMailerMenus
  635.  **
  636.  ** fixes up the all of the menus associated with mailer windows
  637.  **/
  638. void FixMailerMenus(WindowPtr window,WInfoPtr infoPtr)
  639. {
  640.     #pragma unused (infoPtr)
  641.     MenuHandle theMenu;
  642.     Str255 removeMailerText;
  643.     OSErr err;
  644.     SMPMailerState state;
  645.     Boolean undoEnabled;
  646.     
  647.     // get mailer's state so we can set the menus
  648.     
  649.     err = SMPGetMailerState(window, &state);
  650.     if (err != noErr)
  651.         DoError(err);
  652.  
  653.     // edit menu
  654.     
  655.     theMenu = GetMHandle(kEditMenu);
  656.     EnableAllMenuItems(theMenu);
  657.     if (state.isTarget) {
  658.         if (!state.canCut)
  659.             DisableItem(theMenu, kCutItem);
  660.         if (!state.canCopy)
  661.             DisableItem(theMenu, kCopyItem);
  662.         if (!state.canPaste)
  663.             DisableItem(theMenu, kPasteItem);
  664.         if (!state.canClear)
  665.             DisableItem(theMenu, kClearItem);
  666.         if (!state.canSelectAll)
  667.             DisableItem(theMenu, kSelectAllItem);
  668.     }
  669.     else
  670.         FixDrawEditMenu();
  671.  
  672.     // fix undo item
  673.     
  674.     switch (state.undoState) {
  675.         case kSMPMailerUndo:
  676.             SetItem(theMenu,kUndoItem,state.undoWhat);
  677.             EnableItem(theMenu,kUndoItem);
  678.             ClearAppUndo();
  679.             undoEnabled = true;
  680.             break;
  681.         case kSMPUndoDisabled:
  682.             ClearAppUndo();
  683.             undoEnabled = SetupAppUndo();
  684.             break;
  685.         case kSMPAppMayUndo:
  686.             undoEnabled = SetupAppUndo();
  687.             break;
  688.     }
  689.  
  690.     if (state.isTarget && !state.canCut && !state.canCopy && !state.canPaste && !state.canClear &&
  691.         !state.canSelectAll && !undoEnabled)
  692.             DisableItem(theMenu,0);    // disable edit menu title
  693.  
  694.     // mail menu
  695.     
  696.     theMenu = GetMHandle(kMailMenu);
  697.     EnableAllMenuItems(theMenu);
  698.     GetResString(removeMailerText,kRemoveMailerTextID,kRemoveMailerText);
  699.     SetItem(theMenu,kAddRemMailItem,removeMailerText);
  700.     
  701.     if (state.hasBeenReceived)
  702.         DisableItem(theMenu, kSendItem);    // disable send when letter has been received
  703.     else
  704.         DisableItem(theMenu, kForwardItem);    // disable forward when letter has not been received
  705.     
  706.     // disable reply if letter has not been received **and** we didn't just forward it
  707.     
  708.     if (!state.hasBeenReceived && (state.mailerCount==1)) {
  709.         DisableItem(theMenu, kReplyItem);
  710.         DisableItem(theMenu, kReplyToAllItem);
  711.     }
  712.     
  713.     // disable tag if the canTag field is false
  714.     
  715.     if (!state.canTag)
  716.         DisableItem(theMenu, kTagLetterItem);
  717.     
  718.     gMenusDirty = true;
  719. }
  720.  
  721.  
  722. /** DrawImageProc
  723.  **
  724.  ** callback for snapshot image blocks to draw shapes into the snapshot block for a page
  725.  **/
  726. pascal void DrawImageProc(long refCon, Boolean inColor)
  727. {
  728.     #pragma unused (inColor)
  729.     OpenCPicParams newHeader;
  730.     OSErr err;
  731.     Point zeroPt = {0,0};
  732.     WInfoPtr infoPtr;
  733.     TPrInfo prInfo;
  734.     
  735.     infoPtr = (WInfoPtr)refCon;
  736.     prInfo = (**(infoPtr->printRecord)).prInfo;
  737.     
  738.     newHeader.srcRect = prInfo.rPage;
  739.     newHeader.hRes = FixRatio(prInfo.iHRes,1);
  740.     newHeader.vRes = FixRatio(prInfo.iVRes,1);
  741.     newHeader.version = -2;
  742.     newHeader.reserved1 = 0;
  743.     newHeader.reserved2 = 0L;
  744.     
  745.     err = SMPNewPage(&newHeader);
  746.     if (err!=noErr)
  747.         DoError(err);
  748.         
  749.     DrawAllShapes(infoPtr,zeroPt);
  750. }
  751.  
  752.  
  753. /** DrawImageToPicture
  754.  **
  755.  ** called to draw the shapes on a page into a Picture for standard interchange (AppleMail) format
  756.  **/
  757. PicHandle DrawImageToPicture(WindowPtr window,WInfoPtr infoPtr)
  758. {
  759.     PicHandle thePicture;
  760.     RgnHandle saveRgn;
  761.     GrafPtr savePort;
  762.     Point zeroPt = {0,0};
  763.     TPrInfo prInfo;
  764.         
  765.     prInfo = (**(infoPtr->printRecord)).prInfo;
  766.  
  767.     GetPort(&savePort);
  768.     SetPort(window);
  769.     saveRgn = NewRgn();
  770.     GetClip(saveRgn);
  771.     ClipRect(&prInfo.rPage);
  772.     thePicture = OpenPicture(&prInfo.rPage);
  773.     DrawAllShapes(infoPtr,zeroPt);
  774.     ClosePicture();
  775.     SetClip(saveRgn);
  776.     DisposeRgn(saveRgn);
  777.     SetPort(savePort);
  778.     
  779.     return thePicture;
  780. }
  781.  
  782.  
  783. /*------------------------------------------------------------------------------------------*/
  784. /* functions not called outside of this file                                                */
  785. /*------------------------------------------------------------------------------------------*/
  786.  
  787.  
  788. /** AddLetterBlocks
  789.  **
  790.  ** adds snapshot, applemail, and native format blocks to a letter being sent/saved
  791.  **/
  792. OSErr AddLetterBlocks(WindowPtr window,WInfoPtr infoPtr,SMPSendFormat *sendFormat,
  793.                         StringPtr nativeFormatName)
  794. {
  795.     OSErr err = noErr;
  796.     
  797.     // add image (snapshot)
  798.     
  799.     if (!sendFormat || (sendFormat->whichFormats&kSMPImageMask)) {
  800.         err = AddLetterImage(window,infoPtr);
  801.         if (err!=noErr)
  802.             return err;
  803.     }
  804.     
  805.     // add standard letter interchange format (AppleMail)
  806.     
  807.     if (!sendFormat || (sendFormat->whichFormats&kSMPStandardInterchangeMask)) {
  808.         err = AddAppleMailContent(window,infoPtr);
  809.         if (err!=noErr)
  810.             return err;
  811.     }
  812.     
  813.     // add main content enclosure (native)
  814.     
  815.     if (!sendFormat || (sendFormat->whichFormats&kSMPNativeMask)) {
  816.         err = AddNativeContent(window,infoPtr,nativeFormatName);
  817.         if (err!=noErr)
  818.             return err;
  819.     }
  820.     
  821.     return err;
  822. }
  823.  
  824.  
  825. /** AddNativeContent
  826.  **
  827.  ** adds the native format block to a letter by saving the document to a temporary file
  828.  **/
  829. OSErr AddNativeContent(WindowPtr window,WInfoPtr infoPtr,StringPtr nativeFormatName)
  830. {
  831.     OSErr err;
  832.     FSSpec fSpec;
  833.     OCECreatorType blockType;
  834.     
  835.     // save file temporarily so we can add by FSSpec
  836.     
  837.     err = SaveFileToTemp(infoPtr,&fSpec);
  838.     if (err!=noErr)
  839.         return err;
  840.     err = SMPAddMainEnclosure(window,&fSpec);
  841.     FSpDelete(&fSpec);
  842.     
  843.     // add native format name string block
  844.     
  845.     if (err==noErr) {
  846.         blockType.msgCreator = kMailAppleMailCreator;
  847.         blockType.msgType = kSMPNativeFormatName;
  848.         err = SMPAddBlock(window,&blockType,false,&nativeFormatName[1],nativeFormatName[0],
  849.                         kMailFromStart,0);
  850.     }
  851.     
  852.     return err;
  853. }
  854.  
  855.  
  856. /** AddAppleMailContent
  857.  **
  858.  ** adds the standard interchange applemail content to a letter by imaging page to a picture
  859.  **/
  860. OSErr AddAppleMailContent(WindowPtr window,WInfoPtr infoPtr)
  861. {
  862.     OSErr err;
  863.     PicHandle thePicture;
  864.     
  865.     thePicture = DrawImageToPicture(window,infoPtr);
  866.     if (thePicture) {
  867.         HLock((Handle)thePicture);
  868.         err = SMPAddContent(window,kMailPictSegmentType,false,*thePicture,
  869.                 GetHandleSize((Handle)thePicture),nil,true,smRoman);
  870.         KillPicture(thePicture);
  871.     }
  872.     else return kInternalError;
  873.     
  874.     return err;
  875. }
  876.  
  877.  
  878. /** AddLetterImage
  879.  **
  880.  ** adds the snapshot format to a letter by using the SMPImage call which calls my DrawImageProc
  881.  **/
  882. OSErr AddLetterImage(WindowPtr window,WInfoPtr infoPtr)
  883. {
  884.     return SMPImage(window,DrawImageProc,(long)infoPtr,false);
  885. }
  886.  
  887.  
  888. /** HandleExpand
  889.  **
  890.  ** handles the case when the user expands the mailer to full size
  891.  **/
  892. void HandleExpand(WindowPtr window,WInfoPtr infoPtr)
  893. {
  894.     OSErr err;
  895.     Rect rectToInval;
  896.     GrafPtr savePort;
  897.     short expHeight,contHeight,mWidth;
  898.     
  899.     err = SMPGetDimensions(&mWidth,&contHeight,&expHeight);
  900.     if (err!=noErr)
  901.         DoError(err);
  902.         
  903.     infoPtr->otherFlags[kMailerExpanded] = true;
  904.     infoPtr->topIndent = expHeight;
  905.     
  906.     rectToInval = window->portRect;
  907.     rectToInval.top += expHeight;
  908.     rectToInval.bottom -= kScrollBarWidth;
  909.     rectToInval.right -= kScrollBarWidth;
  910.     
  911.     GetPort(&savePort);
  912.     SetPort(window);
  913.     InvalRect(&rectToInval);
  914.     
  915.     MoveScrollBars(window);
  916.  
  917.     err = SMPExpandOrContract(window, true);
  918.     // ignore errors- we may already be expanded
  919.         
  920.     SetPort(savePort);
  921. }
  922.  
  923.  
  924. /** HandleContract
  925.  **
  926.  ** handles the case when the user contracts the mailer to a single line
  927.  **/
  928. void HandleContract(WindowPtr window,WInfoPtr infoPtr)
  929. {
  930.     OSErr err;
  931.     Rect rectToInval;
  932.     GrafPtr savePort;
  933.     short expHeight,contHeight,mWidth;
  934.     
  935.     err = SMPGetDimensions(&mWidth,&contHeight,&expHeight);
  936.     if (err!=noErr)
  937.         DoError(err);
  938.  
  939.     infoPtr->otherFlags[kMailerExpanded] = false;
  940.     infoPtr->topIndent = contHeight;
  941.     
  942.     rectToInval = window->portRect;
  943.     rectToInval.top += contHeight;
  944.     rectToInval.bottom -= kScrollBarWidth;
  945.     rectToInval.right -= kScrollBarWidth;
  946.     
  947.     GetPort(&savePort);
  948.     SetPort(window);
  949.     InvalRect(&rectToInval);
  950.         
  951.     if (!CheckPageSize(window,infoPtr))        // draw area may have gotten too big for us
  952.         MoveScrollBars(window);
  953.     
  954.     // note that we don't call ExpandOrContract() to contract mailer- it's done by mail package
  955.     
  956.     SetPort(savePort);
  957. }
  958.  
  959.  
  960. /** CanCloseLetter
  961.  **
  962.  ** returns true if the given letter can be closed without problems.
  963.  ** also, displays the close options dialog if the user so wishes
  964.  **/
  965. Boolean CanCloseLetter(WindowPtr window)
  966. {
  967.     OSErr err;
  968.     WInfoPtr infoPtr;
  969.     char hState;
  970.     Boolean returnValue;
  971.     
  972.     returnValue = true;
  973.     infoPtr = BeginWindowAccess(window,&hState);
  974.  
  975.     if (IsWindowType(window,kDrawMailerWindow)) {
  976.     
  977.         //    display close options dialog
  978.         
  979.         if (gPreferences.closeOptionsDialog) {
  980.             SetCursor(&qd.arrow);
  981.             err = SMPCloseOptionsDialog(window,&gPreferences.closeOptions);
  982.             if (err!=noErr)
  983.                 returnValue = false;
  984.         }
  985.  
  986.         if (returnValue==true) {
  987.         
  988.             //  close main enclosure (if we're a received letter)
  989.  
  990.             if (infoPtr->fRefNum) {
  991.                 err = FSClose(infoPtr->fRefNum);
  992.                 if (err!=noErr)
  993.                     DoError(err);
  994.                 infoPtr->fRefNum = 0;
  995.             }
  996.             if (infoPtr->resRefNum) {
  997.                 CloseResFile(infoPtr->resRefNum);
  998.                 err = ResError();
  999.                 if (err!=noErr)
  1000.                     DoError(err);
  1001.                 infoPtr->resRefNum = 0;
  1002.             }
  1003.             
  1004.             // see if we can close the letter now
  1005.             
  1006.             err = SMPPrepareToClose(window);
  1007.             if (err==kSMPHasOpenAttachments) {
  1008.                 SetCursor(&qd.arrow);
  1009.                 StopAlert(kHasOpenAttachID,nil);
  1010.                 returnValue = false;
  1011.             }
  1012.             else if (err==kSMPCopyInProgress) {
  1013.                 SetCursor(&qd.arrow);
  1014.                 StopAlert(kCopyInProgress,nil);
  1015.                 returnValue = false;
  1016.             }
  1017.         }
  1018.     }
  1019.     
  1020.     EndWindowAccess(window,hState);
  1021.     return returnValue;
  1022. }
  1023.  
  1024.  
  1025. /** SameLetter
  1026.  **
  1027.  ** returns true if the two letterdescriptors passed in are for the same letter
  1028.  ** (used for getting the adjacent letter)
  1029.  **/
  1030. Boolean SameLetter(const LetterDescriptor *one,const LetterDescriptor *two)
  1031. {
  1032.     if (one->onDisk != two->onDisk)
  1033.         return false;
  1034.     
  1035.     if (one->onDisk) {
  1036.         
  1037.         // compare fsspecs
  1038.         
  1039.         return ((one->u.fileSpec.vRefNum == two->u.fileSpec.vRefNum) &&
  1040.             (one->u.fileSpec.parID == two->u.fileSpec.parID) &&
  1041.             EqualString(one->u.fileSpec.name,two->u.fileSpec.name,false,true));
  1042.     }
  1043.     else {
  1044.         
  1045.         // compare letterspecs
  1046.         
  1047.         return ((one->u.mailboxSpec.spec[0] == two->u.mailboxSpec.spec[0]) &&
  1048.                 (one->u.mailboxSpec.spec[1] == two->u.mailboxSpec.spec[1]) &&
  1049.                 (one->u.mailboxSpec.spec[2] == two->u.mailboxSpec.spec[2]));
  1050.     }
  1051. }